// 测试编译 + 运行
#include "compile.hpp"
#include "run.hpp"
#include <signal.h>

namespace compile_run
{
    using namespace ns_util;
    using namespace ns_compile;
    using namespace ns_run;

    // 退出码转文字信息
    /**
     * code < 0 :内部错误
     * code = 0 :运行成功
     * code > 0 :运行出错，收到信号
     */
    static std::string CodeToMessage(int code, std::string file_name)
    {
        std::string res;
        switch (code)
        {
        case 0:
            res = "运行正常";
            break;
        case -1:
            res = "代码为空";
            break;
        case -2:
            res = "未知错误";
            break;
        case -3:
            //res = "编译出错";
            FileUtil::ReadFile(PathUtil::CompileError(file_name), res);
            break;

        case SIGFPE:
            res = "浮点数溢出";
            break;
        case SIGXCPU:
            res = "时间超限";
            break;

        case SIGABRT:
            res = "空间超限";
            break;

        case SIGSEGV:
            res = "段错误";
            break;
        default:
            res = "bugs";
            break;
        }

        return res;
    }

    class CompileAndRun
    {
        /**
         * 参数：
         * in_json，上层传入的序列化数据,需按照协议完成反序列化转换
         * out_json，返回给上层的运行结果（序列化）
         *
         *
         * in_json反序列化：
         * code:  代码文本
         * input: 用户输入数据（cin） 老师不做，同学自行扩展
         *
         *
         * out_json序列化：
         * 必填（无论运行成功与否）：
         * status：进程退出状态码（信号）
         * reason: 退出原因
         *
         * 选填（若运行成功，填充运行结果）：
         * stdout: 运行完，结果正确
         * stderr: 运行完，结果错误
         *
         *
         * in_json补充：还需传入时间限制和空间限制
         *
         *
         * 最终效果：
         * in_json: {"code": include<>... , "input": , "cpu_limit": , "mem_limit": }
         * out_json: {"status": , "reason": , "stdout": , "stderr": }
         * 
         * 
         * 补充：
         * 如果编译失败，将编译失败信息显示给用户(读compile_err文件)
         */

    public:
        static bool Start(const std::string &in_json, std::string &out_json)
        {
            // LOG(INFO) << "正在进行编译运行..." << std::endl;

            // 反序列化
            Json::Value in_val;
            Json::Reader read;
            read.parse(in_json, in_val);

            std::string code = in_val["code"].asString();
            std::string input = in_val["input"].asString();

            // 时间限制、空间限制
            int cpu_limit = in_val["cpu_limit"].asInt();
            int mem_limit = in_val["mem_limit"].asInt();

            // 反序列化完成，开始编译和运行
            int status_code = 0; // 进程退出状态码（编译 + 运行）

            /**
             * 编译：
             * 生成唯一名称文件
             * 将代码写入文件
             * 执行编译模块
             */

            // 不带路径和后缀的文件名
            // 毫秒级时间戳 + 原子性递增数保证唯一性
            std::string file_name = FileUtil::UniqueFile();

            /**
             * goto：
             * 从调用goto的位置到目的位置之间，不允许有变量：因为该变量是否定义充满不确定性
             */

            int RunCode = 0; // 运行模块状态码

            // 代码为空
            if (code.size() == 0)
            {
                status_code = -1;
                goto End;
            }

            // 代码写入文件
            if (!FileUtil::WriteFile(PathUtil::Src(file_name), code))
            {
                // 写入文件失败，内部错误，不暴露给用户
                status_code = -2; // 表示未知错误
                goto End;
            }

            // 执行编译模块
            if (!Compiler::Compile(file_name))
            {
                status_code = -3;
                goto End;
            }

            /**
             * 运行：
             *
             * 走到这里，说明编译正常完成
             * 运行的返回值（状态码）赋给status_code
             */

            RunCode = Runner::Run(file_name, cpu_limit, mem_limit);

            if (RunCode < 0)
            {
                status_code = -2;
            }

            else if (RunCode > 0)
            {
                status_code = RunCode;
            }

            else
            {
                // 运行成功
                status_code = RunCode;
            }

        End:
            // 序列化
            Json::Value out_val;
            out_val["status"] = status_code;
            out_val["reason"] = CodeToMessage(status_code, file_name);

            //if(status_code == -3) //编译失败
            //{
            //    std::string com_err; 
            //    FileUtil::ReadFile(PathUtil::CompileError(file_name), com_err);
            //    out_val["compile_err"] = com_err;
            //}

            // 若运行成功，则还需要添加stdout、stderr
            if (status_code == 0)
            {
                std::string out;
                FileUtil::ReadFile(PathUtil::Stdout(file_name), out, true);
                out_val["stdout"] = out;

                std::string err;
                FileUtil::ReadFile(PathUtil::Stderr(file_name), err, true);
                out_val["stderr"] = err;
            }

            Json::StyledWriter wr;

            // 由输出型参数接受序列化结果
            out_json = wr.write(out_val);
            
            FileUtil::RemoveTempFile(file_name);
            return true;
        }
    };
}
